package handler

import (
	"encoding/json"
	"fmt"
	"gitee.com/mangenotwork/game-douniu/api/dao"
	"gitee.com/mangenotwork/game-douniu/api/entity"
	"github.com/mangenotwork/common/ginHelper"
	"github.com/mangenotwork/common/log"
	"github.com/mangenotwork/common/utils"
)

func GameConf(c *ginHelper.GinCtx) {
	data, err := new(dao.GameConfDao).Get()
	if err != nil {
		c.APIOutPutError(err, "创建房间失败"+err.Error())
		return
	}
	c.APIOutPut(data, "ok")
	return
}

func NewRoom(c *ginHelper.GinCtx) {
	userIdStr := c.Param("userId")
	userId := utils.AnyToInt64(userIdStr)

	// 创建房间
	roomData, err := new(dao.RoomDao).NewRoom(userId)
	if err != nil {
		c.APIOutPutError(err, "创建房间失败"+err.Error())
		return
	}

	RoomAdd(roomData.RoomId, roomData.UserId)

	_, err = RoomJoin(roomData.RoomId, roomData.UserId)
	if err != nil {
		c.APIOutPutError(err, "创建房间失败"+err.Error())
		return
	}

	roomInfo, err := RoomData(roomData.RoomId)
	if err != nil {
		c.APIOutPutError(err, "创建房间失败"+err.Error())
		return
	}

	// 用户状态记录
	SetUserState(userId, &entity.UserState{State: 1, RoomId: roomData.RoomId})

	c.APIOutPut(roomInfo, "ok")
	return
}

func GetRoomInfo(c *ginHelper.GinCtx) {
	roomIdStr := c.Param("roomId")
	roomId := utils.AnyToInt64(roomIdStr)
	roomInfo, err := RoomData(roomId)
	if err != nil {
		c.APIOutPutError(err, err.Error())
		return
	}
	c.APIOutPut(roomInfo, "ok")
	return

}

func JoinRoom(c *ginHelper.GinCtx) {
	userIdStr := c.GetQuery("user_id")
	userId := utils.AnyToInt64(userIdStr)
	roomIdStr := c.GetQuery("room_id") // 输入的房间号
	roomId := utils.AnyToInt64(roomIdStr)

	_, err := RoomJoin(roomId, userId)
	if err != nil {
		c.APIOutPutError(err, "加入房间失败"+err.Error())
		return
	}
	roomInfo, err := RoomData(roomId)
	if err != nil {
		c.APIOutPutError(err, "加入房间失败"+err.Error())
		return
	}

	// 用户状态记录
	SetUserState(userId, &entity.UserState{State: 1, RoomId: roomId})

	c.APIOutPut(roomInfo, "ok")
	return
}

func UserReadyRoom(c *ginHelper.GinCtx) {
	userIdStr := c.GetQuery("user_id")
	userId := utils.AnyToInt64(userIdStr)
	roomIdStr := c.GetQuery("room_id")
	roomId := utils.AnyToInt64(roomIdStr)
	readyTypeStr := c.GetQuery("ready_type")
	readyTyp := utils.AnyToInt64(readyTypeStr)

	RoomUserReady(roomId, userId, readyTyp)
	roomInfo, err := RoomData(roomId)
	if err != nil {
		c.APIOutPutError(err, "创建房间失败"+err.Error())
		return
	}
	c.APIOutPut(roomInfo, "ok")
	return
}

func UserOutRoom(c *ginHelper.GinCtx) {
	userIdStr := c.GetQuery("user_id")
	userId := utils.AnyToInt64(userIdStr)
	roomIdStr := c.GetQuery("room_id") // 输入的房间号
	roomId := utils.AnyToInt64(roomIdStr)

	RoomOut(roomId, userId)

	// 用户状态记录
	SetUserState(userId, &entity.UserState{State: 0})

	c.APIOutPut("", "退出成功")
	return
}

func DissolutionRoom(c *ginHelper.GinCtx) {
	userIdStr := c.GetQuery("user_id")
	userId := utils.AnyToInt64(userIdStr)
	roomIdStr := c.GetQuery("room_id") // 输入的房间号
	roomId := utils.AnyToInt64(roomIdStr)

	roomInfo, err := RoomData(roomId)
	if err != nil {
		c.APIOutPutError(err, "创建房间失败"+err.Error())
		return
	}

	if roomInfo.Homeowner != userId {
		c.APIOutPutError(fmt.Errorf("只有房主才能解散"), "只有房主才能解散")
		return
	}

	err = RoomDissolution(roomId)
	if err != nil {
		log.Error(err)
	}

	err = new(dao.RoomDao).DissolutionRoom(roomId)
	if err != nil {
		log.Error(err)
	}

	// 用户状态记录
	SetUserState(userId, &entity.UserState{State: 0})

	c.APIOutPut("", "房间解散成功")
	return
}

// 开始游戏 只能房主调用
func GameStart(c *ginHelper.GinCtx) {
	userIdStr := c.GetQuery("user_id")
	userId := utils.AnyToInt64(userIdStr)
	roomIdStr := c.GetQuery("room_id") // 输入的房间号
	roomId := utils.AnyToInt64(roomIdStr)

	roomData := RoomState3(roomId)
	if roomData == nil {
		c.APIOutPutError(fmt.Errorf("房间不存在"), "房间不存在")
		return
	}

	if roomData.Homeowner != userId {
		c.APIOutPutError(fmt.Errorf("只能房主开始游戏"), "只能房主开始游戏")
		return
	}

	gameMatch, err := NewGameMatch(roomId)
	if err != nil {
		c.APIOutPutError(err, err.Error())
		return
	}

	c.APIOutPut(gameMatch, "")
	return
}

// 【准备接口】 状态1(待准备) 所有玩家调用，
func GameReady(c *ginHelper.GinCtx) {
	userIdStr := c.GetQuery("user_id")
	userId := utils.AnyToInt64(userIdStr)
	gameIdStr := c.GetQuery("game_id")
	gameId := utils.AnyToInt64(gameIdStr)

	gameMatch, err := UserReady(gameId, userId)
	if err != nil {
		c.APIOutPutError(err, err.Error())
		return
	}
	c.APIOutPut(gameMatch, "")
	return
}

// 【开始选庄闲接口】状态1(待准备) 由房主调用前置条件是所有玩家准备，状态变更为 2(未确认庄闲)
func GameVocationSelect(c *ginHelper.GinCtx) {
	gameIdStr := c.GetQuery("game_id")
	gameId := utils.AnyToInt64(gameIdStr)

	gameMatch, err := VocationSelectStart(gameId)
	if err != nil {
		c.APIOutPutError(err, err.Error())
		return
	}
	c.APIOutPut(gameMatch, "")
	return
}

// 选庄家
func GameSetMaster(c *ginHelper.GinCtx) {
	userIdStr := c.GetQuery("user_id")
	userId := utils.AnyToInt64(userIdStr)
	gameIdStr := c.GetQuery("game_id")
	gameId := utils.AnyToInt64(gameIdStr)

	gameMatch, err := SetVocation(gameId, userId)
	if err != nil {
		c.APIOutPutError(err, err.Error())
		return
	}
	c.APIOutPut(gameMatch, "")
	return
}

// 发牌: 发牌就是新的一轮游戏， 选完庄 庄家调用，调用一次即可
func GameDeal(c *ginHelper.GinCtx) {
	gameIdStr := c.GetQuery("game_id")
	gameId := utils.AnyToInt64(gameIdStr)

	gameMatch, err := Deal(gameId)
	if err != nil {
		c.APIOutPutError(err, err.Error())
		return
	}
	c.APIOutPut(gameMatch, "")
	return
}

// 下注
func GameBet(c *ginHelper.GinCtx) {
	gameIdStr := c.GetQuery("game_id")
	gameId := utils.AnyToInt64(gameIdStr)
	userIdStr := c.GetQuery("user_id")
	userId := utils.AnyToInt64(userIdStr)
	scoreStr := c.GetQuery("score")
	score := utils.AnyToInt64(scoreStr)

	gameMatch, err := Bet(gameId, userId, score)
	if err != nil {
		c.APIOutPutError(err, err.Error())
		return
	}
	c.APIOutPut(gameMatch, "")
	return
}

// 投降
func GameSurrender(c *ginHelper.GinCtx) {
	gameIdStr := c.GetQuery("game_id")
	gameId := utils.AnyToInt64(gameIdStr)
	userIdStr := c.GetQuery("user_id")
	userId := utils.AnyToInt64(userIdStr)

	gameMatch, err := Surrender(gameId, userId)
	if err != nil {
		c.APIOutPutError(err, err.Error())
		return
	}
	c.APIOutPut(gameMatch, "")
	return
}

// 实时获取游戏状态
func GameState(c *ginHelper.GinCtx) {
	gameIdStr := c.GetQuery("game_id")
	gameId := utils.AnyToInt64(gameIdStr)
	roomIdStr := c.GetQuery("room_id")
	roomId := utils.AnyToInt64(roomIdStr)
	//userIdStr := c.GetQuery("user_id")
	//userId := utils.AnyToInt64(userIdStr)

	data, err := NowGameState(gameId, roomId)
	if err != nil {
		c.APIOutPut(data, err.Error())
		return
	}
	c.APIOutPut(data, "")
	return
}

type GameItemResultData struct {
	UserId      int64                `json:"user_id"`      // 用户id
	NickName    string               `json:"nick_name"`    // 用户名
	Avatar      string               `json:"avatar"`       // 用户头像
	Vocation    int64                `json:"vocation"`     // 玩家庄闲  1:庄  2:闲
	State       int64                `json:"state"`        // 输赢状态  1:赢  非1:输
	Poker       []*entity.PokerData  `json:"poker"`        // 牌信息
	PokerResult *entity.DouNiuResult `json:"poker_result"` // 牌结果
	Score       int64                `json:"score"`        // 本轮游戏的输赢分
	Multiple    int64                `json:"multiple"`     // 对局输赢倍数
	ItemId      int64                `json:"item_id"`      // 当前局数
}

// 【本轮结算结果接口】状态7(本轮结束)所有玩家调用，返回本轮结算结果，未满10轮读秒时间结束后状态变为 3(待发牌)
func GameItemResult(c *ginHelper.GinCtx) {
	gameIdStr := c.GetQuery("game_id")
	gameId := utils.AnyToInt64(gameIdStr)
	itemIdStr := c.GetQuery("item_id")
	itemId := utils.AnyToInt64(itemIdStr)

	out := make([]*GameItemResultData, 0)

	if itemId == 0 {
		gameMatch, err := GetGameMatchObj(gameId)
		if err != nil {
			c.APIOutPutError(err, err.Error())
			return
		}
		itemId = gameMatch.PlayCount
	}

	// 游戏获取当前局，然后 用户id  局数id 游戏id 查询结算数据
	dataList, err := new(dao.GameDao).GetItemResult(itemId, gameId)
	if err != nil {
		c.APIOutPutError(err, err.Error())
		return
	}

	userIds := make([]int64, 0)

	for _, v := range dataList {
		pokerObj := make([]*entity.PokerData, 0)
		pokerResultObj := &entity.DouNiuResult{}
		_ = json.Unmarshal([]byte(v.Poker), &pokerObj)
		_ = json.Unmarshal([]byte(v.PokerResult), &pokerResultObj)
		out = append(out, &GameItemResultData{
			UserId:      v.UserId,
			Vocation:    v.Vocation,     // 玩家庄闲  1:庄  2:闲
			State:       v.State,        // 输赢状态  1:赢  非1:输
			Poker:       pokerObj,       // 牌信息
			PokerResult: pokerResultObj, // 牌结果
			Score:       v.Score,        // 本轮游戏的输赢分 庄家有多条记录记总返回数据
			Multiple:    v.Multiple,     // 对局输赢倍数 闲加输赢显示倍数，庄家有多条记录倍数不显示
			ItemId:      itemId,
		})
		userIds = append(userIds, v.UserId)
	}

	// 添加昵称和头像
	userIds = removeDuplicates(userIds)
	userMap, err := new(dao.UserDao).GetUserMap(userIds)
	if err != nil {
		log.Error(err)
	}

	for _, v := range out {
		if uInfo, ok := userMap[v.UserId]; ok {
			v.NickName = uInfo.NickName
			v.Avatar = uInfo.Avatar
		}
	}

	c.APIOutPut(out, "")
	return
}

type GameFinalResultOut struct {
	FinalResult []*GameFinalResultData `json:"final_result"` // 全局结果
	ItemList    []*GameItemListData    `json:"item_list"`    // 每轮的记录
}

type GameItemListData struct {
	ItemId int64                 `json:"item_id"`
	List   []*GameItemResultData `json:"list"`
}

type GameFinalResultData struct {
	UserId   int64  `json:"user_id"`
	NickName string `json:"nick_name"` // 用户名
	Avatar   string `json:"avatar"`    // 用户头像
	AllScore int64  `json:"all_score"` // 总输赢分数
	Sort     int64  `json:"sort"`      // 庄家显示第一个位置
	Vocation int64  `json:"vocation"`  // 玩家庄闲  1:庄  2:闲
}

// 【本局结算结果接口】 状态8(本局游戏结束) 所有玩家调用 , 时间到状态变为 1(待准备)
func GameFinalResult(c *ginHelper.GinCtx) {
	gameIdStr := c.GetQuery("game_id")
	gameId := utils.AnyToInt64(gameIdStr)
	//userIdStr := c.GetQuery("user_id")
	//userId := utils.AnyToInt64(userIdStr)

	data, err := new(dao.GameDao).GetFinalResult(gameId)
	if err != nil {
		c.APIOutPutError(err, err.Error())
		return
	}

	out := &GameFinalResultOut{
		FinalResult: make([]*GameFinalResultData, 0),
		ItemList:    make([]*GameItemListData, 0),
	}

	userIds := make([]int64, 0)

	sortFunc := func(vocation int64) int64 {
		if vocation == 1 {
			return 9
		}
		return 1
	}

	finalResultMap := make(map[int64]*GameFinalResultData)
	itemMap := make(map[int64][]*GameItemResultData)

	for _, v := range data {

		userIds = append(userIds, v.UserId)

		pokerObj := make([]*entity.PokerData, 0)
		pokerResultObj := &entity.DouNiuResult{}
		_ = json.Unmarshal([]byte(v.Poker), &pokerObj)
		_ = json.Unmarshal([]byte(v.PokerResult), &pokerResultObj)

		final, ok := finalResultMap[v.UserId]
		if !ok {
			finalResultMap[v.UserId] = &GameFinalResultData{
				UserId:   v.UserId,
				AllScore: v.AllScore,           // 总输赢分数
				Sort:     sortFunc(v.Vocation), // 庄家显示第一个位置
				Vocation: v.Vocation,           // 玩家庄闲  1:庄  2:闲
			}
		} else {
			final.AllScore += v.Score
		}

		_, itemOk := itemMap[v.ItemId]
		if !itemOk {
			itemMap[v.ItemId] = make([]*GameItemResultData, 0)
		}

		itemMap[v.ItemId] = append(itemMap[v.ItemId], &GameItemResultData{
			UserId:      v.UserId,
			Vocation:    v.Vocation,     // 玩家庄闲  1:庄  2:闲
			State:       v.State,        // 输赢状态  1:赢  非1:输
			Poker:       pokerObj,       // 牌信息
			PokerResult: pokerResultObj, // 牌结果
			Score:       v.Score,        // 本轮游戏的输赢分 庄家有多条记录记总返回数据
			Multiple:    v.Multiple,     // 对局输赢倍数 闲加输赢显示倍数，庄家有多条记录倍数不显示
			ItemId:      v.ItemId,
		})

	}

	for _, v := range finalResultMap {
		out.FinalResult = append(out.FinalResult, v)
	}

	for k, v := range itemMap {

		out.ItemList = append(out.ItemList, &GameItemListData{
			ItemId: k,
			List:   v,
		})
	}

	// 添加昵称和头像
	userIds = removeDuplicates(userIds)
	userMap, err := new(dao.UserDao).GetUserMap(userIds)
	if err != nil {
		log.Error(err)
	}
	for _, v := range out.FinalResult {
		if uInfo, ok := userMap[v.UserId]; ok {
			v.NickName = uInfo.NickName
			v.Avatar = uInfo.Avatar
		}
	}
	for _, v := range out.ItemList {
		for _, i := range v.List {
			if uInfo, ok := userMap[i.UserId]; ok {
				i.NickName = uInfo.NickName
				i.Avatar = uInfo.Avatar
			}
		}
	}

	c.APIOutPut(out, "")
	return
}

type UserGameRecordOut struct {
	Total int64                    `json:"total"`
	List  []*entity.UserGameRecord `json:"list"`
}

func UserGameRecord(c *ginHelper.GinCtx) {
	userIdStr := c.GetQuery("user_id")
	userId := utils.AnyToInt64(userIdStr)
	pageStr := c.GetQuery("page")
	page := utils.AnyToInt64(pageStr)
	limitStr := c.GetQuery("limit")
	limit := utils.AnyToInt64(limitStr)

	count, data, err := new(dao.GameDao).GetUserGameResult(userId, page, limit)
	if err != nil {
		c.APIOutPutError(err, err.Error())
		return
	}

	out := &UserGameRecordOut{
		Total: count,
		List:  data,
	}

	for _, v := range out.List {
		if v.Score > 0 {
			v.Win = 1
		}
		v.CreatedAtStr = utils.Timestamp2Date(v.CreatedAt)
	}

	c.APIOutPut(out, "")
	return
}

// 换牌接口
func GameChange(c *ginHelper.GinCtx) {
	gameIdStr := c.GetQuery("game_id")
	gameId := utils.AnyToInt64(gameIdStr)
	userIdStr := c.GetQuery("user_id")
	userId := utils.AnyToInt64(userIdStr)
	niuTypeStr := c.GetQuery("type") //1炸弹2五小3金牛4银牛5牛牛6有牛7没牛 61牛1 62牛2 63牛3
	niuType := utils.AnyToInt64(niuTypeStr)

	_, newPoker, err := ChangePoker(gameId, userId, niuType)
	if err != nil {
		c.APIOutPutError(err, err.Error())
		return
	}
	c.APIOutPut(newPoker, "")
	return
}

func removeDuplicates(userIDs []int64) []int64 {
	processed := make(map[int64]struct{})
	uniqUserIDs := make([]int64, 0)
	for _, uid := range userIDs {
		if _, ok := processed[uid]; ok {
			continue
		}
		uniqUserIDs = append(uniqUserIDs, uid)
		processed[uid] = struct{}{}
	}
	return uniqUserIDs
}
